package com.example.exceldemo.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.handler.inter.IExcelExportServer;
import cn.afterturn.easypoi.handler.inter.IWriter;
import cn.hutool.poi.excel.ExcelUtil;
import com.example.exceldemo.entity.User;
import com.example.exceldemo.exception.ServiceException;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author xiaohuang
 * @Date 2024/9/10
 */
public class EasyPoiUtils {
    private final static Logger logger= LoggerFactory.getLogger(ExcelUtil.class);

    private static final String CHARSET_UTF8 = "utf-8";

    /**
     * 导出Excel报表
     *
     * @param titleName 报表标题名称
     * @param sheetName 工作表名称
     * @param poiClass 实体类的Class对象，用于导出操作
     * @param list 要导出的数据列表
     * @param fileName 导出文件的名称
     * @param style 是否使用自定义样式，true为使用，false为不使用
     * @param createHeader 是否创建表头标题，true为创建，false为不创建
     */
    public static void export(String titleName, String sheetName, Class<?> poiClass, Collection<?> list, String fileName,boolean style,boolean createHeader) {
        // 获取HttpServletResponse对象
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        // 创建ExportParams对象，传入报表标题和工作表名称
        ExportParams exportParams = new ExportParams(titleName, sheetName);
        // 根据style参数决定是否设置自定义样式
        if (style)
            exportParams.setStyle(ExcelStyleUtil.class);
        //是否创建表头标题
        if (!createHeader)
            exportParams.setCreateHeadRows(false);
        //创建ExcelExportUtil对象，传入参数为ExportParams对象
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams,poiClass, list);
        //导出到浏览器
        setContentType(response, fileName);
        // 尝试写入文件，并处理异常
        try (ServletOutputStream fileOutputStream = response.getOutputStream();) {
            // 将workbook写入到文件输出流中
            workbook.write(fileOutputStream);
        } catch (IOException e) {
            // 异常处理
            throw new ServiceException("文件写入失败: " + e.getMessage());
        } finally {
            // 关闭workbook
            try {
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                throw new ServiceException("关闭workbook失败: " + e.getMessage());
            }
        }
    }

    public static void initExport(String titleName, String sheetName, List<ExcelExportEntity> list, Collection<?> dataSet, String fileName, boolean style, boolean createHeader) {
        // 获取HttpServletResponse对象
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        // 创建ExportParams对象，传入报表标题和工作表名称
        ExportParams exportParams = new ExportParams(titleName, sheetName);
        //exportParams.setType(ExcelType.XSSF);
        // 根据style参数决定是否设置自定义样式
        if (style)
            exportParams.setStyle(ExcelStyleUtil.class);
        //是否创建表头标题
        if (!createHeader)
            exportParams.setCreateHeadRows(false);
        //创建ExcelExportUtil对象，传入参数为ExportParams对象
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, list,dataSet);
        //导出到浏览器
        exportWorkbookExcel(response, workbook, fileName);

    }
    /**
     * 根据指定的参数和数据导出Excel文档,将全部数据分开放到多个sheet
     *
     * @param titleName 表格标题名称
     * @param sheetName 工作表名称
     * @param poiClass 数据模型类类型，用于导出操作
     * @param list 要导出的数据列表
     * @param fileName 导出文件的名称
     * @param pageSize 每页数据条数
     */
    public static void manySheetExport(String titleName, String sheetName, Class<?> poiClass, List<?> list, String fileName,int pageSize) {
        // 获取HttpServletResponse对象，用于输出Excel文件
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        // 创建ExportParams对象，设置表格标题和工作表名称
        ExportParams exportParams = new ExportParams(titleName, sheetName);
        // 计算总页数，用于分页导出
        int totalPage = (list.size() % pageSize ==0)?list.size() / pageSize: list.size() / pageSize+1;
        Workbook workbook = null;
        // 使用ExcelExportUtil导出大型Excel文档
        workbook = ExcelExportUtil.exportBigExcel(exportParams, poiClass, new IExcelExportServer() {
            /**
             * obj 是总页数，作为限制条件
             * page 是当前页数，随着分页处理逐渐增加
             */
            @Override
            public List<Object> selectListForExcelExport(Object obj, int page) {
                // 重要！此方法体的目的是将所有数据分批返回处理，以避免内存溢出
                if (page > totalPage) {
                    return null;
                }
                // 计算当前页的数据索引范围
                int fromIndex = (page - 1) * pageSize;
                int toIndex = page != totalPage ? fromIndex + pageSize :list.size();
                List<Object> copyList = new ArrayList<>();
                // 复制当前页的数据到copyList
                copyList.addAll(list.subList(fromIndex, toIndex));
                return copyList;
            }
        }, totalPage);

        // 调用方法将Workbook对象导出为Excel文件
        exportWorkbookExcel(response, workbook, fileName);
    }




    /**
     * 导入Excel数据到指定的实体类列表中
     *
     * @param fileInputStream Excel文件的输入流
     * @param pojoClass 实体类的Class对象，用于指定导入数据后实体类的类型
     */
    public static void importExcel(InputStream fileInputStream, Class<?> pojoClass){
       //ExcelImportUtil.importExcel已关闭流
        try (InputStream fis = fileInputStream) {
            // 创建导入参数配置
            ImportParams importParams = new ImportParams();
            // 设置标题行数
            importParams.setTitleRows(1);
            // 设置表头行数
            importParams.setHeadRows(1);

            // 使用配置好的参数和输入流导入Excel数据到实体类列表中
            List<User> users = ExcelImportUtil.importExcel(fis, pojoClass, importParams);

            logger.info("导入数据：{}", users); // 添加实际的日志参数
        } catch (Exception e) {
            logger.error("导入数据时发生错误", e);
            throw new ServiceException("导入数据时发生错误:", e);
        }
    }
    /**
     * 导出Excel工作簿
     *
     * @param response HTTP响应对象，用于输出Excel文件
     * @param workbook 要导出的Excel工作簿对象
     * @param fileName 导出文件的名称，需要是合法的文件名
     */
    public static void exportWorkbookExcel(HttpServletResponse response, Workbook workbook, String fileName) {
        // 验证文件名是否合法，防止XSS攻击
        ServletOutputStream out =null;
        try {// 设置响应头信息
             out = response.getOutputStream();
            response.setCharacterEncoding(CHARSET_UTF8);
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
            // 导出Excel
            workbook.write(out);
        } catch (IOException e) {
            // 异常处理
            e.printStackTrace();
            // 可以在这里记录日志或者返回错误信息给调用者
            throw new ServiceException("导出异常："+ e.getMessage());
        }finally {
            try {
                if (workbook != null) {
                    workbook.close();
                }
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置HTTP响应的内容类型和文件下载头部信息
     * 该方法主要用于准备下载Excel文件，指定文件名和编码方式
     *
     * @param response HTTP响应对象，用于设置响应头和字符编码
     * @param fileName 文件名，将用于下载文件的默认名称
     */
    public static void setContentType(HttpServletResponse response, String fileName) {
        try {
            // 设置响应的字符编码为UTF-8，确保兼容性
            response.setCharacterEncoding(CHARSET_UTF8);
            // 设置内容类型为Excel文件，并指定字符集为utf-8
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            // 设置文件下载的头部信息，包括文件名
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        } catch (UnsupportedEncodingException e) {
            // 如果编码方式不被支持，抛出自定义异常
            throw new ServiceException("设置ContentType失败: " + e.getMessage());
        }
    }
}
